package cate.game.pvp.eliterace.simulator;

import cate.common.table.d.GDFight;
import cate.game.pvp.eliterace.data.EliteRaceKV;
import cate.game.pvp.eliterace.data.EliteRaceRecord;
import cate.game.pvp.eliterace.data.EliteRaceSpec;
import cate.game.pvp.eliterace.handler.*;
import cate.game.pvp.eliterace.timer.EliteRaceTimerTask.Settings;
import org.apache.commons.compress.utils.Lists;

import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;

import static cate.game.pvp.eliterace.util.EliteRaceSpecUtils.getKoFlag;
import static cate.game.pvp.eliterace.util.EliteRaceSpecUtils.isMatchKoSimulator;


public class BothEliteRaceKoSimulator extends BaseEliteRaceBetSimulator {
    private final List<EliteRaceRecord> nextRecordList = Lists.newArrayList();

    public BothEliteRaceKoSimulator(Supplier<EliteRaceKV> kvSupplier,
                                    Supplier<EliteRaceRecordOperation> recordOperationSupplier,
                                    Supplier<EliteRacePsOperation> psOperationSupplier,
                                    Supplier<EliteRaceFightOperation> fightOperationSupplier,
                                    Supplier<EliteRaceRankRwdOperation> rankRwdOperationSupplier,
                                    Supplier<EliteRaceBetOperation> betOperationSupplier,
                                    Supplier<EliteRaceVideoOperation> videoOperationSupplier) {
        super(
                kvSupplier,
                recordOperationSupplier,
                psOperationSupplier,
                fightOperationSupplier,
                rankRwdOperationSupplier,
                betOperationSupplier,
                videoOperationSupplier
        );
    }

    @Override
    protected int getPeriodFlag(Settings settings) {
        return getKoFlag(settings);
    }

    @Override
    public boolean isMatch(Settings settings) {
        return isMatchKoSimulator(settings);
    }

    @Override
    public void afterRunWith() {
        EliteRaceRecordOperation recordOperation = getRecordOperation();
        nextRecordList.forEach(recordOperation::addRecord);
        nextRecordList.clear();
    }

    @Override
    protected List<EliteRaceRecord> query(Settings settings) {
        List<EliteRaceRecord> recordList = Lists.newArrayList();
        EliteRaceRecordOperation recordOperation = getRecordOperation();
        EliteRaceSpec spec = settings.getSpec();
        for (byte i = 0; i < 4; i++) {
            EliteRaceSpec querySpec = EliteRaceSpec.of(
                    spec.getSeason(),
                    spec.getPeriod(),
                    i,
                    spec.getRound(),
                    (byte) 0
            );
            List<EliteRaceRecord> queryList = recordOperation.query(querySpec);
            recordList.addAll(queryList);
        }
        return recordList;
    }

    @Override
    protected void afterHandleFightTask(EliteRaceRecord recordTask) {
        EliteRaceSpec spec = recordTask.getSpec();
        if (spec.getRound() < 3) {
            byte winner = recordTask.getWinner();
            EliteRaceSpec nSpec = EliteRaceSpec.of(
                    spec.getSeason(),
                    spec.getPeriod(),
                    spec.getGroup(),
                    (byte) (spec.getRound() + 1),
                    (byte) 0);
            byte nIndex = (spec.getRound() == 1)
                    ? (byte) (recordTask.getIndex() % 2 == 0 ? 1 : 0)
                    : (byte) (recordTask.getIndex() / 2);
            EliteRaceRecord nRecord = nextRecordList.stream()
                    .filter(rd -> rd.getIndex() == nIndex && rd.getSpec().equals(nSpec))
                    .findAny()
                    .orElse(null);
            if (Objects.isNull(nRecord)) {
                nRecord = EliteRaceRecord.of(nSpec, null, null);
                nRecord.setIndex(nIndex);
                nextRecordList.add(nRecord);
            }
            String wUid = (winner == GDFight.Team.A)
                    ? recordTask.getIdA()
                    : recordTask.getIdB();
            if (spec.getRound() == 1) {
                if (recordTask.getIndex() == 1 || recordTask.getIndex() == 2) {
                    nRecord.setIdA(wUid);
                } else {
                    nRecord.setIdB(wUid);
                }
            } else {
                if (recordTask.getIndex() % 2 == 0) {
                    nRecord.setIdA(wUid);
                } else {
                    nRecord.setIdB(wUid);
                }
            }
        }
    }
}
